<template>
    <Dropdown
        ref="dropdown"
        trigger="custom"
        placement="bottom-start"
        @on-clickoutside="handleDropdownOut"
        :visible="dropdown.visible">

        <div>
            <i-button
                size="small"
                @click="dropdown.visible = !dropdown.visible">选择房间</i-button>
        </div>

        <div class="rs-rooms-container" v-show="result.length">
            <Tag v-for="r in result" :key="r">{{r}}</Tag>
        </div>

        <DropdownMenu slot="list" class="rs-rooms-wrap">
            <Dropdown
                trigger="custom"
                :visible="dropdown[floor]"
                placement="right-start"
                v-for="(rooms, floor) in roomsModel"
                :key="floor"
                @on-click="handleDropdown">

                <DropdownItem :name="floor">
                    <input
                        type="checkbox"
                        :disabled="rooms.disabled"
                        @change="e => handleSelectAll(e, floor)"
                        v-model="rooms.checked"/>
                    <span>
                        {{floor === 'default' ? '公区' : '第' + floor+ '层'}}
                    </span>
                    <Icon type="ios-arrow-right"></Icon>
                </DropdownItem>

                <DropdownMenu
                    class="dropdown"
                    slot="list"
                    style="width:180px;max-height: 320px;overflow-y: auto;">
                    <DropdownItem v-for="room in rooms.children" :key="room.id">
                        <label class="rs-rooms-label" :for="'cb' + room.id">
                            <input
                                :id="'cb' + room.id"
                                type="checkbox"
                                v-model="room.checked"
                                :disabled="roomHasTheDevice(room, deviceType, rooms).fill"/>
                            <span>
                                {{room.room_name == 'default' ? '公区' : room.room_name}}
                                {{roomHasTheDevice(room, deviceType, rooms).message}}
                            </span>
                        </label>
                    </DropdownItem>
                </DropdownMenu>

            </Dropdown>
        </DropdownMenu>
    </Dropdown>
</template>

<script>
/**
 * 预约工单 房间级联多选组件
 */
export default {
  name: 'room-selector',
  props: {
    value: Array,
    rooms: Array,
    deviceType: {
      required: true
    }
  },
  watch: {
    rooms: {
      deep: true,
      handler (n) {
        this.transferData()
      }
    },
    roomsModel: {
      deep: true,
      handler (n) {
        this.queueUpdate(function () {
          const result = []
          Object.values(n).forEach(floorRooms => {
            floorRooms.children.forEach(room => {
              if (room.checked) {
                result.push({
                  name: room.room_name,
                  id: room.id
                })
              }
            })
          })
          this.result = result.map(r => r.name)
          this.$emit('input', result.map(r => r.id))
        })
      }
    }
  },
  data () {
    return {
      dropdown: {
        visible: false
      },
      roomsModel: {},
      result: [],
      qId: 0,
      queue: {},
      currentName: ''
    }
  },
  mounted () {
    if (this.rooms && this.rooms.length) {
      this.transferData()
    }
  },
  methods: {
    queueUpdate (fn) {
      this.queue[this.qId] = fn
      this.$nextTick(() => {
        if (this.queue[this.qId]) {
          fn.call(this)
          this.queue[this.qId] = null
          this.qId++
        }
      })
    },
    $resetModel () {
      this.dropdown = {
        visible: false
      }
      this.roomsModel = {}
      this.result = []
      this.$emit('input', [])
    },
    $setModel (roomIds) {
      this.result = []
      Object.keys(this.roomsModel).forEach(floor => {
        this.roomsModel[floor].children.forEach((room, index) => {
          if (roomIds && roomIds.includes(room.id)) {
            this.$set(this.roomsModel[floor].children[index], 'checked', true)
            this.result.push(room.room_name)
            if (room.room_name === '公区') {
              this.$set(this.roomsModel[floor], 'checked', true)
            }
          } else {
            this.$set(this.roomsModel[floor].children[index], 'checked', false)
          }
        })
      })
      this.handleDropdown()
    },
    /**
         * 转换房间列表Array为this.roomsModel {
         *  floor/default: {
         *      checked: false,
         *      children: [{
         *          id, room_name, devicesType, checked
         *      }]
         *    }
         * }
         * 这样的结构
         * 其中devicesType在父组件中将room.devices转换而来
         *
         * this.dropdown则为 {floor/default: false} 这样的控制dropdown显示对象
         */
    transferData () {
      let haveDefaultRoom = false
      const result = {}
      const floors = [...new Set(this.rooms.map(item => item.floor))]
      this.rooms.forEach(room => {
        if (room.room_name === '公区') {
          result['default'] = {
            checked: false,
            children: [
              {
                id: room.id,
                room_name: room.room_name,
                devicesType: room.devicesType,
                checked: false
              }
            ]
          }
          haveDefaultRoom = true
          return
        }
        if (!result[room.floor]) {
          result[room.floor] = {
            checked: false,
            children: []
          }
        }
        result[room.floor].children.push({
          id: room.id,
          room_name: room.room_name,
          devicesType: room.devicesType,
          checked: false
        })
      })
      floors.forEach(floor => {
        this.$set(this.dropdown, floor, false)
      })
      if (haveDefaultRoom) {
        this.$set(this.dropdown, 'default', false)
      }
      this.roomsModel = result
    },
    /**
         * 预约工单的设备类型独立于其他地方的设备类型,
         * 其中类型4无网关门锁即为门锁, 通过门锁上限判断
         */
    roomHasTheDevice (room, type, parentRoom) {
      if (type === 4) type = 2
      let result = { message: '', fill: false }
      if (Object.keys(room.devicesType).includes(type + '')) {
        result.message = ' [已有该设备]'
      }
      const data = {
        2: 1, // 门锁上限1个
        3: 4, // 电表上限4个
        4: 1, // 无网关门锁不限
        6: 2, // 水表上限2个
        7: 2 // 水表上限2个
      }
      if (data[type] <= room.devicesType[type]) {
        result.message = ' [设备达到上限]'
        result.fill = true
        this.$nextTick(() => {
          room.checked = false
        })
      }
      return result
    },
    /**
         * 主动监听全选checkbox的变化
         * 在下拉点击时间中会有冲突, 所以主动监听
         */
    handleSelectAll (e, floor) {
      this.qId++
      let val = e.target.checked
      const newModel = JSON.parse(JSON.stringify(this.roomsModel))
      newModel[floor].children.forEach((room, index) => {
        room.checked = val
      })
      this.roomsModel = newModel
    },
    handleDropdownOut (e) {
      if (!this.$refs.dropdown.$el.contains(e.target)) {
        for (let i in this.dropdown) {
          this.dropdown[i] = false
        }
      }
    },
    /**
         * 点击 DropdownItem 时候触发
         * 通过对比this.dropdown的floor显示值决定
         * @params {[undefined,Number]} 传入的 DropdownItem name选项
         * 1. 值为undefined的时候, 只通过楼层下的房间是否全部checked来控制楼层是否全选
         * 2. 如果dropdown里这个值为true, 说明已打开
         * 3. 如果dropdown里这个值为false, 则打开新的子列表,
         *    如果点击的是checkbox, 同时触发handleDropdown和handleSelectAll
         */
    handleDropdown (name) {
      if (!name) {
        this.$nextTick(() => {
          Object.keys(this.roomsModel).forEach(floor => {
            let allChecked = true
            this.roomsModel[floor].children.forEach(room => {
              if (room.checked === false) allChecked = false
            })
            this.$set(this.roomsModel[floor], 'checked', allChecked)
          })
        })
        return
      }
      this.currentName = name
      if (this.dropdown[name]) {
        return
      }
      for (let i in this.dropdown) {
        if (i !== 'visible') this.dropdown[i] = false
      }
      setTimeout(() => {
        this.dropdown[name] = true
      }, 300)
    }
  }
}
</script>

<style lang="less">
.rs-rooms-wrap {
    width: 140px;
    max-width: 300px;
    &.ivu-dropdown-menu .ivu-dropdown-rel + .ivu-select-dropdown {
        width: auto;
    }
}

.rs-rooms-container {
    margin-bottom: -10px;
    max-height: 100px;
    overflow-y: auto;
}

.rs-rooms-label {
    display: inline-block;
    width: 100%;
}
</style>